#include "client_conn.h"

#include <iostream>

using namespace std;

ClientConn::ClientConn(asio::io_service& ioservice_, UdpService& udpservice, client_options opt_)
: BaseConn(ioservice_, udpservice)
, opt(opt_)
{
}

void ClientConn::handleTcpAccept()
{
	cout << "Handling tcp accept, from: " << tcpconn.remote_endpoint() << endl;
	udpconn.async_connect(opt.udp_server_addr,
		boost::bind(&ClientConn::handleUdpConnect, this, token, boost::asio::placeholders::error)
	);
}

void ClientConn::handleUdpConnect(Token tk, const boost::system::error_code& e)
{
	if (e || !token) {
		cerr << "Failed to connect to udp (" << opt.udp_server_addr << "): " << e.message() << endl;
		close();
		return;
	}

	cout << "Connected udp socket, to: " << udpconn.remote_endpoint() << endl;

	asio::async_read(udpconn, boost::asio::buffer(recvbuf, 4),
		boost::bind(&ClientConn::handleReadHeader, this, token, boost::asio::placeholders::error)
	);
}

void ClientConn::handleReadHeader(Token tk, const boost::system::error_code& e)
{
	if (e || !token) {
		cerr << "Failed to read header: " << e.message() << endl;
		close();
		return;
	}

	uint16 maxver =
		(recvbuf[0] <<  8) |
		(recvbuf[1] <<  0);

	uint32 extralen =
		(recvbuf[2] <<  8) |
		(recvbuf[3] <<  0);

	if (extralen > 500) {
		cerr << "Invalid read header" << endl;
		close();
		return;
	}

	asio::async_read(udpconn, boost::asio::buffer(recvbuf, extralen*2),
		boost::bind(&ClientConn::handleReadVersion, this, token, boost::asio::placeholders::error, maxver, extralen)
	);
}

void ClientConn::handleReadVersion(Token tk, const boost::system::error_code& e, int maxver, int extralen)
{
	if (e || !token) {
		cerr << "Failed to read versions: " << e.message() << endl;
		close();
		return;
	}

	if (maxver == 0) {
		cerr << "Remote does not support needed version" << endl;
		close();
		return;
	}

	uint32 header = 0x00000000;
	sendbuf[0] = (header >>  8) & 0xff;
	sendbuf[1] = (header >>  0) & 0xff;

	asio::async_write(udpconn, boost::asio::buffer(sendbuf, 2),
		boost::bind(&ClientConn::handleSentHeader, this, token, boost::asio::placeholders::error)
	);
}

void ClientConn::handleSentHeader(Token tk, const boost::system::error_code& e)
{
	if (e || !token) {
		cerr << "Failed to send header: " << e.message() << endl;
		close();
		return;
	}

	startForwarding();
}
